feat(integrations): add integrations settings#4541
Conversation
a2bf584 to
76aa8b3
Compare
39a7855 to
04f1105
Compare
| */ | ||
| public function register_settings_fields() { | ||
| $fields = []; | ||
| if ( ! Audience_Integrations::is_enabled() || ! Reader_Activation::is_esp_configured() ) { |
There was a problem hiding this comment.
One thing I wasn't certain about is whether we wanted to move the main esp configuration (api keys) into the integration. I opted to only move sync settings here and leave the main configuration in newsletter settings since newsletters should be usable without sync.
There was a problem hiding this comment.
Pull request overview
This PR adds a settings framework for reader activation integrations. It allows integrations (starting with the ESP integration) to declare settings fields that are stored as WordPress options and managed via a new Audience Integrations admin page, gated behind a NEWSPACK_INTEGRATIONS_SETTINGS_ENABLED constant.
Changes:
- New
Audience_Integrationswizard class with REST API endpoints (GET /settings,POST /settings,POST /settings/{id}/enabled) for managing integration settings Integrationbase class extended withsettings_fields,register_settings_fields()abstract method, settings getters/setters, metadata prefix management, and a unifiedget_settings_config()API method- Renaming of
OPTION_PREFIX→INCOMING_FIELDS_OPTION_PREFIX,get_selected_fields()→get_incoming_fields(),set_selected_fields()→set_incoming_fields()
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
includes/reader-activation/integrations/class-integration.php |
Core: adds settings fields framework, metadata prefix management, renames incoming fields constants/methods, merges get_enabled_outgoing_fields_raw_keys() and get_enabled_outgoing_fields_prefixed_keys() into unified get_enabled_outgoing_fields_keys($prefixed) |
includes/reader-activation/integrations/class-esp.php |
Implements register_settings_fields(), get_provider(), get_list_options(), get_master_list_id(); adds feature flag branching in can_sync(), push_contact_data(), get_incoming_available_contact_fields() |
includes/reader-activation/class-integrations.php |
Adds get_all_integration_settings() and update_integration_settings() static methods; changes ESP auto-enable logic |
includes/reader-activation/class-reader-activation.php |
Routes ESP settings through the integration when feature flag is on |
includes/reader-activation/sync/class-metadata.php |
Routes get_prefix() through ESP integration when flag is on; renames method references in deprecated methods |
includes/reader-activation/integrations/class-contact-pull.php |
Updates renamed method calls from get_selected_fields() to get_incoming_fields() |
includes/wizards/audience/class-audience-integrations.php |
New wizard file providing admin page and REST API endpoints |
src/wizards/audience/views/integrations/index.js |
New React UI for the Integrations settings page |
src/wizards/index.tsx |
Conditionally registers the new integrations page component |
src/wizards/types/window.d.ts |
TypeScript type declaration for newspackAudienceIntegrations global |
includes/class-newspack.php |
Includes the new wizard file |
includes/class-wizards.php |
Instantiates Audience_Integrations wizard |
tests/unit-tests/integrations/class-test-integrations.php |
Adds new tests for metadata prefix, settings config, and renames test method names |
tests/unit-tests/integrations/class-sample-integration.php |
Implements register_settings_fields() abstract method |
tests/unit-tests/integrations/class-failing-sample-integration.php |
Implements register_settings_fields() abstract method (with a bug) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
I had a look at the design update from Thomas and had a go at re-implementing this, but decided it might be better to push out what I have already and update the UI in a follow-up PR. |
I had a first pass at the code... I think we are touching more things than we should be. The prefix was intentionally left as a global option in #4544... and all those metadata methods are super fragile Let's connect tomorrow and look at this together |
leogermani
left a comment
There was a problem hiding this comment.
I gave it a thorough review now, and this is looking good. I left some comments in the code.
One of the points is that I think we should avoid that check to see if the new UI is enabled or not in order to route the fetching and setting of the settings. We should do something similar we did here.
The ideas is that we deprecate these global settings, and then route them to the ESP integration. First time we try to fetch them, we migrate the values from the global settings to the ESP integration setting.
This is cool because then the two UIs can actually exist while we are still in development and the transition is seamless. People will already be tweaking the ESP integration settings from the OLD UI - This is already what happens with enabled_outgoing_fields.
At first I thought we could leave the prefix as a global option. But it wasn't such a strong opinion. Now that you've done it, I think it's fine.
The UI for the incoming fields should also be a list of checkboxes. The available values come from get_incoming_available_contact_fields (that could be renamed to get_available_incoming_contact_fields)
| $provider = $this->get_provider(); | ||
|
|
||
| // For Mailchimp, filter out groups and tags, only include remote lists. | ||
| if ( 'mailchimp' === $provider ) { |
There was a problem hiding this comment.
Mailchimp has a handy method to do that:
function get_lists( $audiences_only = false ) {
| 'ras_esp_master_list_id_not_found', | ||
| __( 'ESP master list ID is not set.', 'newspack-plugin' ) | ||
| ); | ||
| if ( Audience_Integrations::is_enabled() ) { |
There was a problem hiding this comment.
We shouldn't have this check. We should automatically route everything to the integration. For now, this ESP integration will be enabled by default
| } | ||
|
|
||
| $master_list_id = Reader_Activation::get_esp_master_list_id(); | ||
| if ( Audience_Integrations::is_enabled() ) { |
There was a problem hiding this comment.
Again we should not have this check. We should migrate the options to the integration the first time we try to fetch it. Like we did here:
| public function set_selected_fields( $fields ) { | ||
| return \update_option( self::OPTION_PREFIX . $this->id, array_values( $fields ) ); | ||
| public function get_enabled_outgoing_fields() { | ||
| return array_values( \get_option( self::OUTGOING_FIELDS_OPTION_PREFIX . $this->id, Sync\Metadata::get_default_fields() ) ); |
There was a problem hiding this comment.
The default currently is an empty array. I think that's better
There was a problem hiding this comment.
Hmm, I haven't changed the default for this one. Here it is in trunk:
newspack-plugin/includes/reader-activation/integrations/class-integration.php
Lines 257 to 259 in 6284fc6
But I went ahead and updated this to an empty array in 71e2e25
| */ | ||
| public function get_selected_fields() { | ||
| return \get_option( self::OPTION_PREFIX . $this->id, [] ); | ||
| public function get_incoming_fields() { |
There was a problem hiding this comment.
should be get_enabled_incoming_fields?
There was a problem hiding this comment.
I originally renamed this while looking at the POC which allowed users to enter any field values. But seeing this has changes, I've renamed all of the relevant methods to get_enabled_...
| */ | ||
| public function get_enabled_outgoing_fields() { | ||
| return array_values( \get_option( self::OUTGOING_FIELDS_OPTION_PREFIX . $this->id, Sync\Metadata::get_default_fields() ) ); | ||
| public function update_incoming_fields( $fields ) { |
There was a problem hiding this comment.
should be update_enabled
| */ | ||
| public static function get_prefix() { | ||
| // When the integrations feature is enabled, read prefix from the ESP integration. | ||
| if ( \Newspack\Audience_Integrations::is_enabled() ) { |
There was a problem hiding this comment.
remove this check and directly route it to the esp integration like we did in other methods in this class
|
|
||
| // hardcode ESP integration as enabled for now. | ||
| self::enable( 'esp' ); | ||
| // Auto-enable all integrations if the option has never been saved. |
There was a problem hiding this comment.
This was arbitrarily done by Claude and I never revisited. I reverted this to hardcode ESP in 5fa536a
| } | ||
|
|
||
| // When integration settings are enabled, route ESP settings to the integration. | ||
| if ( Audience_Integrations::is_enabled() ) { |
There was a problem hiding this comment.
Let's avoid this check and simply route the settings that we moved to the esp integration directly
5d22ba4 to
8a6fb10
Compare
|
Thanks for the review @leogermani! Just noting I've tackled most of the feedback, but ran into one small issue while making changes and I'm out of time today so will have to pick this back up tomorrow. |
99af4ba to
11cdebd
Compare
11cdebd to
61341a8
Compare
5e0149c to
0faff0a
Compare
0faff0a to
71e2e25
Compare
|
This one is ready for another look @leogermani One other issue I ran into while accounting for fetching incoming fields is, when the admin changes the metadata prefix, the incoming fields get populated with fields which contain the old prefix. For example, For the time being I decided to tackle this in a follow-up PR, but let me know if you prefer I do this here instead. |
Got it. I think this is a non-issue... part of the challenges of dealing with complex data flows. If someone ever changes the prefix, they might have to do some cleanup in the data in the integration |
| } | ||
| $list_options = $this->get_list_options(); | ||
| $provider = $this->get_provider(); | ||
| switch ( $provider->service ) { |
There was a problem hiding this comment.
$provider can be null. Wouldn't this throw an alert or error here?
| do_action( 'newspack_reader_activation_register_integrations' ); | ||
|
|
||
| // hardcode ESP integration as enabled for now. | ||
| // hardcode ESP integration as enabled for now.. |
| * @return string | ||
| */ | ||
| public static function get_prefix() { | ||
| $esp_integration = Integrations::get_integration( 'esp' ); |
There was a problem hiding this comment.
let's add a deprecation doc comment and an explanation at the doc block like we did to the other methods
| return $fields; | ||
| } | ||
|
|
||
| if ( $filtered ) { |
There was a problem hiding this comment.
I this is not specific to the ESP integration. We should have this filter on the Integration abstraction, like it was... no?
So the integration implementation just grab all the fields, and our framework will automatically filter out our own fields from the list
There was a problem hiding this comment.
I initially moved this thinking we could allow individual integrations to apply their own filtering logic for any special cases. But you're right that it makes more sense to live in the integration abstraction.
I moved it back in 07960ce
|
Hey @chickenn00dle, good job getting this PR merged! 🎉 Now, the Please check if this PR needs to be included in the "Upcoming Changes" and "Release Notes" doc. If it doesn't, simply remove the label. If it does, please add an entry to our shared document, with screenshots and testing instructions if applicable, then remove the label. Thank you! ❤️ |
This fixes a fatal that resulted in calling the incorrect is_enabled method in #4541

All Submissions:
Changes proposed in this Pull Request:
Closes https://linear.app/a8c/issue/NPPD-1325/framework-allow-integrations-to-declare-settings-fields-plus-prototype
Adds a settings framework for reader activation integrations. Integrations can now declare settings fields (text, checkbox, select, number, textarea, password) that are stored as WordPress options and managed via a new Audience Integrations admin page.
This PR also adds a prototype UI that mostly copies the UI for sync in Audience > Configuration.
Backend:
Integrationbase class: newsettings_fieldsproperty, getter/setter methods with type-aware sanitization,register_settings_fieldsfor declaring settings fields, andget_settings_config()for API responses.Integrations: newget_all_integration_settings()andupdate_integration_settings()static methods.Audience_Integrationswizard: REST API endpoints (GET /settings,POST /settings) gated behind aNEWSPACK_INTEGRATIONS_SETTINGS_ENABLEDfeature flag.Frontend:
How to test the changes in this Pull Request:
Before testing, make sure either Automattic/newspack-newsletters#2028 has been merged, or you checkout the branch.
NEWSPACK_INTEGRATIONS_SETTINGS_ENABLEDflag towp-config.php. Also enabled logging to more easily identify sync data in the logs (define( 'Newspack_Log_Level', 3 );)n build newspack-plugin.settings_fieldsappear with their fields rendered correctly.wp-config.phpand confirm the page no longer appears.Other information: